//
//  TTXMLObject.m
//  Tint
//
//  Created by Kevin Wu on 2/27/12.
//  Copyright (c) 2012 Telligenty. All rights reserved.
//

#import "TTXMLObject.h"
#import <objc/runtime.h>


@implementation NSObject (XMLObject)

+ (id)objectWithXMLData:(NSData *)XMLData {
    
    TTXML *xml = [TTXML XMLWithXMLData:XMLData];
    TTXMLNode *root = [xml rootElement];
    
    Class cls = [self classForNodeName:root.name];
    if (cls) {
        return [cls objectWithXMLNode:root];
    }
    
    return nil;
}

+ (NSObject *)objectWithXMLNode:(TTXMLNode *)XMLNode {
    
    if (XMLNode == nil) return nil;
    
    id object = [[self alloc] init];
    
    
    NSDictionary *propertyMap = [self propertyMap];
    NSEnumerator *nameEnumerator = [propertyMap keyEnumerator];
    NSString *nodeName = nil;
    while ((nodeName = [nameEnumerator nextObject])) {
        
        NSString *propertyName = [propertyMap objectForKey:nodeName];
        id propertyValue = nil;
        
        
        TTXMLNode *node = [[XMLNode elementsForName:nodeName] firstObject];
        if (node) {
            Class cls = [self classForNodeName:node.name];
            if (cls) propertyValue = [cls objectWithXMLNode:node];
            else propertyValue = node.value;
        }
        
        TTXMLNode *attr = [XMLNode attributeForName:nodeName];
        if (attr) propertyValue = attr.value;
        
        
        if (propertyValue == nil) continue;
        
        NSString *attribute = [self attributeForProperty:propertyName];
        
        if ([attribute hasPrefix:@"Tc"]) { // BOOL: Tc
            BOOL value = NO;
            if ([propertyValue respondsToSelector:@selector(boolValue)])
                value = [propertyValue boolValue];
            [object setValue:[NSNumber numberWithBool:value] forKey:propertyName];
        } else if ([attribute hasPrefix:@"Ti"]) { // int: Ti
            int value = 0;
            if ([propertyValue respondsToSelector:@selector(intValue)])
                value = [propertyValue intValue];
            [object setValue:[NSNumber numberWithInt:value] forKey:propertyName];
        } else if ([attribute hasPrefix:@"Tq"]) { // long long: Tq
            long long value = 0;
            if ([propertyValue respondsToSelector:@selector(longLongValue)])
                value = [propertyValue longLongValue];
            [object setValue:[NSNumber numberWithLongLong:value] forKey:propertyName];
        } else if ([attribute hasPrefix:@"Td"]) { // double: Td
            double value = 0.0;
            if ([propertyValue respondsToSelector:@selector(doubleValue)])
                value = [propertyValue doubleValue];
            [object setValue:[NSNumber numberWithDouble:value] forKey:propertyName];
        } else if ([attribute hasPrefix:@"T@\"NSString\""]) { // NSString: T@"NSString"
            NSString *value = nil;
            if ([propertyValue isKindOfClass:[NSString class]])
                value = propertyValue;
            [object setValue:value forKey:propertyName];
        } else if ([attribute hasPrefix:@"T@\"NSDate\""]) { // NSDate: T@"NSDate"
            NSDate *value = nil;
            if ([propertyValue doubleValue]>0.0)
                value = [NSDate dateWithUNIXTimeString:propertyValue];
            [object setValue:value forKey:propertyName];
        } else {
            [object setValue:propertyValue forKey:propertyName];
        }
        
    }
    
    return [object autorelease];
}


+ (void)mapToNodeName:(NSString *)nodeName {
    [[self translationDictionary] setObject:NSStringFromClass([self class]) forKeyIfNotNil:nodeName];
}

//+ (void)setClass:(Class)cls forNodeName:(NSString *)nodeName {
//    [[self translationDictionary] setObject:NSStringFromClass(cls) forKeyIfNotNil:nodeName];
//}

+ (Class)classForNodeName:(NSString *)nodeName {
    NSString *className = [[self translationDictionary] objectForKey:nodeName];
    return NSClassFromString(className);
}

+ (NSMutableDictionary *)translationDictionary {
    static NSMutableDictionary *sharedTranslationDictionary = nil;
    if (sharedTranslationDictionary == nil) {
        sharedTranslationDictionary = [[NSMutableDictionary alloc] init];
    }
    return sharedTranslationDictionary;
}


#pragma mark - To override

+ (NSDictionary *)propertyMap {
    return nil;
}

@end



@implementation NSArray (XMLObject)

+ (NSArray *)objectWithXMLNode:(TTXMLNode *)XMLNode {
    
    if (XMLNode == nil) return nil;
    
    NSMutableArray *object = [NSMutableArray array];
    
    TTXMLNode *node = [XMLNode firstChild];
    while (node) {
        
        id value = nil;
        
        Class cls = [self classForNodeName:node.name];
        if (cls) value = [cls objectWithXMLNode:node];
        else value = node.value;
        
        if (value) [object addObject:value];
        
        node = [node nextSibling];
    }
    
    if (TTIsArrayWithItems(object)) {
        return [NSArray arrayWithArray:object];
    }
    
    return nil;
}

@end



@implementation NSDictionary (XMLObject)

+ (NSDictionary *)objectWithXMLNode:(TTXMLNode *)XMLNode {
    
    if (XMLNode == nil) return nil;
    
    NSMutableDictionary *object = [NSMutableDictionary dictionary];
    
    TTXMLNode *node = [XMLNode firstChild];
    while (node) {
        
        id value = nil;
        
        Class cls = [self classForNodeName:node.name];
        if (cls) value = [cls objectWithXMLNode:node];
        else value = node.value;
        
        if (value) [object setObject:value forKey:node.name];
        
        node = [node nextSibling];
    }
    
    if (TTIsDictionaryWithItems(object)) {
        return [NSDictionary dictionaryWithDictionary:object];
    }
    
    return nil;
}

@end
